home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 February: Tool Chest / Dev.CD Feb 97 TC.toast / Sample Code / QuickTime / JPEG Sample / JPEG.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-22  |  10.6 KB  |  488 lines  |  [TEXT/CWIE]

  1. /*************************************************************************************
  2. #
  3. #        JPEG.c
  4. #
  5. #        This segment handles JPEG.
  6. #
  7. #        Author(s):     Michael Marinkovich & Guillermo Ortiz
  8. #                    Apple Developer Technical Support
  9. #                    marink@apple.com
  10. #
  11. #        Modification History: 
  12. #
  13. #            4/3/96        MWM     Initial coding                     
  14. #
  15. #        Copyright © 1992-96 Apple Computer, Inc., All Rights Reserved
  16. #
  17. #
  18. #        You may incorporate this sample code into your applications without
  19. #        restriction, though the sample code has been provided "AS IS" and the
  20. #        responsibility for its operation is 100% yours.  However, what you are
  21. #        not permitted to do is to redistribute the source as "DSC Sample Code"
  22. #        after having made changes. If you're going to re-distribute the source,
  23. #        we require that you make it clear in the source that the code was
  24. #        descended from Apple Sample Code, but that you've made changes.
  25. #
  26. *************************************************************************************/
  27.  
  28. #include <Events.h>
  29. #include <ToolUtils.h>
  30. #include <Gestalt.h>
  31. #include <OSUtils.h>
  32. #include <Palettes.h>
  33.  
  34. #include "App.h"
  35. #include "Proto.h"
  36.  
  37.  
  38. // data unload buffer size
  39. #define kBufferSize            2048
  40.  
  41.  
  42. //----------------------------------------------------------------------
  43. //
  44. //    Globals - 
  45. //
  46. //----------------------------------------------------------------------
  47.  
  48. extern Boolean        gInBackground;
  49.  
  50.  
  51. //----------------------------------------------------------------------
  52. //
  53. //    ReadJPEG - open a JPEG file with supplied FSSpec.
  54. //                    
  55. //
  56. //----------------------------------------------------------------------
  57.  
  58. OSErr ReadJPEG(FSSpec spec, CGrafPtr *newWorld)
  59. {
  60.     OSErr            err = noErr;
  61.     Handle            tempHandle;
  62.     Handle            newHandle;
  63.     GWorldPtr        theWorld = nil;
  64.     short            refNum;
  65.     long            fileSize;
  66.     Size            pictSize;
  67.     
  68.     
  69.     if (newWorld != nil)
  70.     {
  71.         SetCursor(*GetCursor(watchCursor));            // set the cursor to a watch while busy
  72.             
  73.         err = FSpOpenDF(&spec, fsRdWrShPerm, &refNum);
  74.         if ( err == noErr ) 
  75.         {
  76.             err = GetEOF(refNum, &fileSize );
  77.             if ( err == noErr ) 
  78.             {
  79.                 tempHandle = NewHandle(fileSize);
  80.                 if (tempHandle == nil) 
  81.                 {
  82.                     tempHandle = TempNewHandle(fileSize, &err);        // allocate space for picture
  83.                 }
  84.                 
  85.                 if ( err == noErr && tempHandle != nil ) 
  86.                 {
  87.                     HLock(tempHandle);
  88.                     err = FSRead(refNum, &fileSize, *tempHandle);    // read in the pict data
  89.                     HUnlock(tempHandle);
  90.                 }
  91.             }
  92.             FSClose(refNum);                    // close the file
  93.             
  94.             err = ConvertJPEG(tempHandle, &theWorld);
  95.             *newWorld = theWorld;
  96.     
  97.         }    
  98.             
  99.         SetCursor(&qd.arrow );                // set cursor back to arrow
  100.     }
  101.     else
  102.         err = paramErr;
  103.         
  104.             
  105.     return err;
  106.  
  107. }
  108.  
  109.  
  110. //----------------------------------------------------------------------
  111. //
  112. //    ConvertJPEG - Convert JPEG data to a GWorld.
  113. //
  114. //
  115. //----------------------------------------------------------------------
  116.  
  117. OSErr ConvertJPEG(Handle image, CGrafPtr *newWorld) 
  118. {
  119.     OSErr                    err = noErr;
  120.     GWorldPtr                oldPort;
  121.     GWorldPtr                theWorld;
  122.     GDHandle                oldGD;
  123.     PixMapHandle            thePix;
  124.     ImageDescriptionHandle     desc = nil;
  125.     Rect                    bounds;
  126.  
  127.     GetGWorld(&oldPort, &oldGD);
  128.     
  129.     HLock((Handle)image);
  130.     desc = (ImageDescriptionHandle)NewHandle(sizeof(ImageDescription));
  131.     
  132.     if (desc != nil)
  133.     {
  134.         err = GetJPEGDescription(image, desc, &bounds);
  135.         if (err == noErr)
  136.         {
  137.             err = NewJPEGWorld(&theWorld, (*desc)->depth, bounds);
  138.             
  139.             if (theWorld != nil && err == noErr) 
  140.             {
  141.                 thePix = GetGWorldPixMap(theWorld);
  142.                 LockPixels(thePix);
  143.                 SetGWorld(theWorld, nil);
  144.                 
  145.                 err = DecompressImage(*image, desc, thePix, &bounds, &bounds, srcCopy, nil);
  146.                         
  147.                 UnlockPixels(thePix);     
  148.                 
  149.                 if (err == noErr)
  150.                     *newWorld = theWorld;
  151.                         
  152.             }
  153.             DisposeHandle((Handle)desc);
  154.         }
  155.               
  156.     }
  157.  
  158.     SetGWorld(oldPort, oldGD);
  159.  
  160.     return err;
  161. }
  162.  
  163.  
  164. //----------------------------------------------------------------------
  165. //
  166. //    GetJPEGDescription -
  167. //
  168. //
  169. //----------------------------------------------------------------------
  170.  
  171. OSErr GetJPEGDescription(Handle image, ImageDescriptionHandle desc, Rect *bounds)
  172. {
  173.     OSErr                    err = noErr;
  174.     Fixed                    xRes,yRes;
  175.     long                     i;
  176.     long                     imageSize;
  177.     unsigned char             *buffer;
  178.     char                     JIFF[5];
  179.     short                     w = 0, h = 0;
  180.     short                    units;
  181.     short                    version;
  182.     short                     components;
  183.  
  184.     buffer = (unsigned char *)(*image);
  185.     imageSize = GetHandleSize((Handle)image);
  186.     
  187.     for (i = 0; i < imageSize; i++ ) 
  188.     {
  189.         if (buffer[i] == 0xff) 
  190.         {
  191.             i++;
  192.             if (buffer[i] == 0xc0)         // start of frame header marker
  193.             {        
  194.                 i += 4;
  195.                 h = (buffer[i]<<8) | buffer[i+1];
  196.                 i += 2;
  197.                 w = (buffer[i]<<8) | buffer[i+1];
  198.                 i += 2;
  199.                 if ( w && h )             // make sure we do have something to display
  200.                 {
  201.                     /* now make up the image description */
  202.                     (*desc)->idSize = sizeof(ImageDescription);
  203.                     (*desc)->temporalQuality = 0;
  204.                     (*desc)->spatialQuality = codecNormalQuality;
  205.                     (*desc)->dataSize = imageSize;
  206.                     (*desc)->cType = 'jpeg';
  207.                     (*desc)->version = 0;
  208.                     (*desc)->revisionLevel = 0;
  209.                     (*desc)->vendor = 0;
  210.                     (*desc)->width = w;
  211.                     (*desc)->height = h;
  212.                     (*desc)->clutID = -1;
  213.                     BlockMove("\pPhoto - JPEG",(*desc)->name,13);
  214.                     (*desc)->hRes = xRes;
  215.                     (*desc)->vRes = yRes;
  216.                     
  217.                     components = buffer[i++];
  218.                     
  219.                     switch (components) 
  220.                     {
  221.                         case 3:
  222.                             (*desc)->depth = 32;
  223.                             break;
  224.                             
  225.                         case 1:        
  226.                             (*desc)->depth = 40;
  227.                             break;
  228.                             
  229.                         default:
  230.                             break;
  231.                     }
  232.     
  233.                     SetRect(bounds, 0, 0, w, h);
  234.                     // we have our info so we want to get out
  235.                     return err;
  236.                 }
  237.             }
  238.             if (buffer[i] == 0xe0) // JFIF marker
  239.             {
  240.                 i += 3;
  241.                 JIFF[0] = buffer[i++];
  242.                 JIFF[1] = buffer[i++];
  243.                 JIFF[2] = buffer[i++];
  244.                 JIFF[3] = buffer[i++];
  245.                 JIFF[4] = buffer[i++];
  246.                 
  247.                 // check if we really have the JFIF header
  248.                 if ( JIFF[0] == 'J' && JIFF[1] == 'F'  && JIFF[2] == 'I'  && JIFF[3] == 'F' ) 
  249.                 {
  250.                       version = (buffer[i]<<8) | buffer[i+1];
  251.                       i += 2;
  252.     
  253.                     if ( version < 0x100 )
  254.                     {    
  255.                         err = paramErr;
  256.                         break;     // don't know this
  257.                     }
  258.                     
  259.                     units = buffer[i++];
  260.                     xRes = (buffer[i]<<8) | buffer[i+1];
  261.                       i += 2;
  262.                     yRes = (buffer[i]<<8) | buffer[i+1];
  263.                       i += 2;
  264.         
  265.                     switch ( units ) 
  266.                     {
  267.                         case 0:            // no res, just aspect ratio
  268.                             xRes = FixMul(72L << 16, xRes << 16);
  269.                             yRes = FixMul(72L << 16, yRes << 16);
  270.                             break;
  271.                             
  272.                         case 1:            // dots per inch
  273.                             xRes = xRes << 16;
  274.                             yRes = yRes << 16;
  275.                             break;
  276.                             
  277.                         case 2:            // dots per centimeter (we convert to dpi )
  278.                             xRes = FixMul(0x28a3d, xRes << 16);
  279.                             yRes = FixMul(0x28a3d, xRes << 16);
  280.                             break;    
  281.                             
  282.                         default:
  283.                             break;
  284.                     }
  285.                 }
  286.             }
  287.         }        
  288.     }
  289.  
  290.     return err;
  291. }
  292.  
  293.  
  294. //----------------------------------------------------------------------
  295. //
  296. //    NewJPEGWorld -
  297. //
  298. //
  299. //----------------------------------------------------------------------
  300.  
  301. OSErr NewJPEGWorld(GWorldPtr *theWorld, short depth, Rect theRect)
  302. {
  303.     OSErr            err = noErr;
  304.     GWorldPtr        oldPort;
  305.     PixMapHandle    thePix;
  306.     CTabHandle        cTab = nil;
  307.     GDHandle        oldGD;
  308.     
  309.     if (theWorld != nil)
  310.     {
  311.         GetGWorld(&oldPort,&oldGD);
  312.     
  313.         // if depth is greater than 32 then the 
  314.         // image is grayscale
  315.         if (depth > 32) 
  316.         {
  317.             cTab = GetCTable(depth);
  318.             depth = depth - 32;
  319.         }
  320.         
  321.         err = NewGWorld(theWorld, depth, &theRect, cTab, nil, 0L);    // try our heap
  322.         
  323.         if (err != noErr)
  324.             err = NewGWorld(theWorld, depth, 
  325.                             &theRect, cTab, nil, useTempMem);    // else try temp
  326.     
  327.         if (err == noErr && theWorld != nil) 
  328.         {
  329.             thePix = GetGWorldPixMap(*theWorld);
  330.                     
  331.             if (LockPixels(thePix)) 
  332.             {
  333.                 SetGWorld(*theWorld, nil);
  334.                 EraseRect(&theRect);
  335.                 
  336.                 UnlockPixels(thePix);
  337.             }
  338.         }
  339.         
  340.         SetGWorld(oldPort, oldGD);    
  341.     }
  342.     else
  343.         err = paramErr;
  344.         
  345.     return err;
  346.     
  347. }
  348.  
  349.  
  350. //----------------------------------------------------------------------
  351. //
  352. //    DoSaveJPEG -
  353. //
  354. //
  355. //----------------------------------------------------------------------
  356.  
  357. OSErr DoSaveJPEG(WindowRef window)
  358. {
  359.     OSErr                        err = noErr;
  360.     StandardFileReply            reply;
  361.     ImageDescriptionHandle         desc;
  362.     Handle                        data;
  363.     Str255                        str;
  364.     Rect                        srcRect;
  365.     GWorldPtr                    theWorld;
  366.     PixMapHandle                thePix;
  367.     CTabHandle                    cTab = nil;
  368.     ICMFlushProcRecord            flushProc;
  369.     long                        size;
  370.     long                        dataSize;
  371.     short                        refNum;
  372.     short                        depth;
  373.     Str255                         title;
  374.     DocHnd                        doc;
  375.     
  376.  
  377.     GetWTitle(window, title);
  378.     StandardPutFile("\pSave document as:", title, &reply) ;
  379.     
  380.     doc = (DocHnd)GetWRefCon(window);
  381.     
  382.     if (reply.sfGood && doc != nil)
  383.     {
  384.         desc = (ImageDescriptionHandle)NewHandle(sizeof(ImageDescription));
  385.  
  386.         theWorld = (**doc).world;
  387.         
  388.         if (theWorld != nil && desc != nil) 
  389.         {
  390.             srcRect = theWorld->portRect;
  391.             thePix = GetGWorldPixMap(theWorld);
  392.             if (LockPixels(thePix)) 
  393.             {    
  394.                 // if less than 16-bit then get the color table
  395.                 // of our GWorld
  396.                 depth = (**thePix).pixelSize;
  397.                 if (depth < 16)
  398.                     cTab = (**thePix).pmTable;
  399.                 
  400.                 err = GetMaxCompressionSize(thePix, &srcRect, depth,
  401.                                             codecNormalQuality, 'jpeg',
  402.                                             bestCompressionCodec, &size);
  403.                 if (err == noErr)
  404.                 {
  405.                     data = NewHandle(size);
  406.                     err = MemError();
  407.                     
  408.                     if (data != nil && err == noErr) 
  409.                     {
  410.                         HLock(data);
  411.                                                                      
  412.                         if (reply.sfReplacing ) 
  413.                             err = FSpDelete(&reply.sfFile);
  414.                     
  415.                         err = FSpCreate(&reply.sfFile, 'JVWR', 'JPEG', reply.sfScript);
  416.                         
  417.                         if (err == noErr)
  418.                             err = FSpOpenDF(&reply.sfFile,fsRdWrPerm, &refNum);
  419.                             
  420.                         if (err == noErr)
  421.                             err = SetFPos(refNum, fsFromStart , 0);
  422.                             
  423.                         if (err == noErr)
  424.                         {
  425.                             flushProc.flushProc = NewICMFlushProc(DataUnloadProc);
  426.                             flushProc.flushRefCon = refNum;
  427.  
  428.                             err = FCompressImage(thePix, &srcRect, depth,
  429.                                                  codecNormalQuality, 'jpeg',
  430.                                                  bestCompressionCodec, cTab,
  431.                                                  codecFlagWasCompressed, kBufferSize,
  432.                                                  &flushProc, nil, desc, *data);
  433.                         }
  434.                             
  435.                         if (err == noErr)
  436.                             err = SetFPos(refNum, fsFromStart, (**desc).dataSize);
  437.      
  438.                         if (err == noErr)
  439.                             err = SetEOF(refNum, (**desc).dataSize);
  440.                                      
  441.                         if (err == noErr)        
  442.                             err = FSClose( refNum );
  443.                         
  444.                         HUnlock(data);
  445.                         DisposeHandle(data);
  446.                         
  447.                         DisposeRoutineDescriptor(flushProc.flushProc);
  448.                     }
  449.                 }    
  450.             }
  451.             
  452.             UnlockPixels(thePix);
  453.         
  454.         }
  455.         DisposeHandle((Handle)desc);
  456.     }
  457.     else
  458.         err = dsMemFullErr;
  459.     
  460.     return err;
  461.     
  462. }            
  463.     
  464.     
  465.  
  466. //----------------------------------------------------------------------
  467. //
  468. //    DataUnloadProc -
  469. //
  470. //
  471. //----------------------------------------------------------------------
  472.  
  473. pascal OSErr DataUnloadProc(Ptr data, long bytesNeeded, long refCon)
  474. {
  475.     OSErr        err;
  476.     
  477.     if (data == nil)
  478.     {
  479.         err = SetFPos(refCon, fsCurPerm , bytesNeeded);
  480.     }
  481.     else
  482.     {    
  483.         err = FSWrite(refCon, &bytesNeeded, data);
  484.     }
  485.     
  486.     return err;
  487.     
  488. }